import { EcsComponent } from "./EcsComponent";
import { EcsEntity } from "./EcsEntity";
import { EcsEntityGroup } from "./EcsEntityGroup";
import { EcsWorld } from "./EcsWorld";

/**组件快照 */
export class EcsComponentSnapshot {
    public compId: number;
    public data: any;

    static fromComponent(comp: EcsComponent) {
        let snapshot = new EcsComponentSnapshot();
        snapshot.compId = EcsComponent.getId(comp);
        snapshot.data = JSON.parse(JSON.stringify(comp));
        return snapshot;
    }
}

/**实体快照 */
export class EcsEntitySnapshot {
    public id: number;
    public groupId: string;
    public components: EcsComponentSnapshot[] = [];

    static fromEntity(entity: EcsEntity) {
        let snapshot = new EcsEntitySnapshot();
        snapshot.id = entity.id;
        snapshot.groupId = entity._factory.groupId
        entity.componentMap.forEach((comp) => {
            snapshot.components.push(EcsComponentSnapshot.fromComponent(comp));

        })
        return snapshot;
    }
}

/**实体快照 */
export class EcsGroupSnapshot {
    public entityIds: number[] = [];
    public compIds: number[] = [];
    public compIdMap: { [key: number]: boolean } = {};
    public indexMap: { [key: number]: number } = {}

    static fromGroup(group: EcsEntityGroup) {
        let snapshot = new EcsGroupSnapshot();
        snapshot.entityIds = group.entities.map(e => e.id)
        snapshot.compIds = group.compIds;
        snapshot.compIdMap = group.compIdMap;
        snapshot.indexMap = group.indexMap;
        return snapshot;
    }
}

/**世界快照 */
export class EcsWorldSnapshot {
    public frame: number;
    public nextEntityGenId: number;
    public left_elapsed: number
    public singletons: any[] = [];
    public entities: EcsEntitySnapshot[] = [];
    public groups: EcsGroupSnapshot[] = []

    static fromWorld(world: EcsWorld) {
        let snapshot = new EcsWorldSnapshot();
        snapshot.frame = world.frameCount;
        snapshot.nextEntityGenId = world.nextEntityGenId;
        snapshot.left_elapsed = world.leftElapsed

        for (let index = 0; index < world.singletons.length; index++) {
            const singleton = world.singletons[index];
            if (singleton) {
                snapshot.singletons.push(JSON.parse(JSON.stringify(singleton)));
            }
        }


        for (const key in world.entities) {
            if (Object.prototype.hasOwnProperty.call(world.entities, key)) {
                const entity = world.entities[key];
                snapshot.entities.push(EcsEntitySnapshot.fromEntity(entity));
            }
        }

        world.groupMap.forEach(group => {
            snapshot.groups.push(EcsGroupSnapshot.fromGroup(group))
        })

        return snapshot;
    }

    /**还原世界 */
    static restoreWorld(world: EcsWorld, snapshot: EcsWorldSnapshot) {

        for (let index = 0; index < snapshot.singletons.length; index++) {
            Object.assign(world.singletons[index], snapshot.singletons[index])
        }

        for (const key in snapshot.entities) {
            if (Object.prototype.hasOwnProperty.call(snapshot.entities, key)) {
                const entitySnapshot = snapshot.entities[key];
                let entity = world.entities[entitySnapshot.id];
                const compClzs = entitySnapshot.components.map(compSnapshot => EcsComponent.getComponentType(compSnapshot.compId))
                entity = world.addEntityWithComps(compClzs, null, entitySnapshot.id);
                entitySnapshot.components.forEach(compSnapshot => {
                    let comp = entity.componentMap.get(compSnapshot.compId);

                    Object.assign(comp, compSnapshot.data);
                })
                // for (let index = 0; index < entitySnapshot.components.length; index++) {
                //     const compSnapshot = entitySnapshot.components[index];

                //     // entity.__comps[compSnapshot.compId] = comp;
                //     // entity.__componentsID += Math.pow(2, compSnapshot.compId);
                // }
            }
        }


        snapshot.groups.forEach(groupSnapshot => {
            const group = world.getGroupByCompIds(...groupSnapshot.compIds)
            group.compIds = groupSnapshot.compIds
            group.compIdMap = groupSnapshot.compIdMap
            group.indexMap = groupSnapshot.indexMap
            group.entities.length = 0
            groupSnapshot.entityIds.forEach(id => {
                group.entities.push(world.entities[id])
            })


        })

        world.frameCount = snapshot.frame;
        world.leftElapsed = snapshot.left_elapsed

        world.systems.forEach(s => s.updateCount = world.frameCount)
        world.nextEntityGenId = snapshot.nextEntityGenId;
    }
}